#ifndef CMD_PARSER_H
#define CMD_PARSER_H

#include "cmd_view.h"

#ifdef WIN32 
#include <conio.h>
#endif 
#include <ctype.h>

#include <boost/spirit/core.hpp>
#include <boost/spirit/phoenix/primitives.hpp>
#include <boost/spirit/phoenix/operators.hpp>
#include <boost/spirit/attribute.hpp>
#include <boost/spirit/actor.hpp>
#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/dynamic.hpp>

namespace vpm
{
	namespace cmo 
	{
		using namespace boost::spirit;
		using namespace phoenix;

		static rule<>  keyword_r    = +(alpha_p - space_p); 
		static rule<>  namedvalue_r = +(alpha_p - space_p);

		//unit : keyword , [keyword] ,(namedvalue)
		struct KeywordReader
		{
			KeywordReader(CmdView & cmdView,CmdNode::NodeType type,CmdExecutorPtr & pExecutor):m_cmdView(cmdView),m_pExecutor(pExecutor)
			{
				m_nodeType = type; 				
			}
			void operator() ( const char * beg, const char * end) const
			{
				std::string keyword(beg,end);
				m_cmdView.add_keyword(keyword,m_nodeType,m_pExecutor);
			}

			CmdNode::NodeType m_nodeType;
			CmdView        & m_cmdView; 
			CmdExecutorPtr &m_pExecutor;
		};

		struct KeywordAction
		{
			KeywordAction(CmdView & cmdView,CmdExecutorPtr & pExecutor):m_cmdView(cmdView),m_pExecutor(pExecutor)
			{
			}
			void operator()(const char * beg, const char * end) const 
			{
				m_cmdView.add_action(m_pExecutor);
			}

			CmdView        & m_cmdView; 
			CmdExecutorPtr & m_pExecutor;
		};

		/*
		The command executor should be the last word of the command. 
		*/
		class CmdParser : public grammar<CmdParser>
		{
		public:
			CmdParser(CmdView & cmdView, CmdExecutorPtr& pExecutor):m_cmdView(cmdView),m_pExecutor(pExecutor)
			{
				cmdView.reset();
			}

			template <typename ScannerT>
			struct definition
			{
				definition(CmdParser const & self)
				{
					r_expression =+(( keyword_r[KeywordReader(self.m_cmdView,CmdNode::KeyWord, self.m_pExecutor)] >> *blank_p)
						|( confix_p(ch_p('['),keyword_r[KeywordReader(self.m_cmdView,CmdNode::Optional, self.m_pExecutor)],']') >> *blank_p) 
						|( confix_p(ch_p('('),namedvalue_r[KeywordReader(self.m_cmdView,CmdNode::NamedValue, self.m_pExecutor)],ch_p(')')) >>*blank_p))   
						>> end_p[KeywordAction(self.m_cmdView,self.m_pExecutor)];
				}

				rule<ScannerT> const & start()
				{
					return r_expression;
				}

				rule<ScannerT> r_expression;		
			};

		private:
			CmdView        & m_cmdView;			
			CmdExecutorPtr & m_pExecutor; 
		};
	}
}

#endif //   




